/*
* 
* Fichier source projet intel Acceler8 sous license GNU GPL v3.
* Voir http://www.gnu.org/copyleft/gpl.html pour plus d'informations
* La license est egalement disponible dans le repertoire /doc
* 
* Cree le : mardi 15 novembre 2011 à 15 : 18.
* Auteurs : Axel MOINET et Arnaud DURAND.
* 
* Nom de fichier : filtrecalculsoussequence.cpp
* Chemin du fichier : ./src/classes/filtrecalculsoussequence/filtrecalculsoussequence.cpp
* 
* Description :
* 
*/

#include "filtrecalculsoussequence.h"

filtreCalculSousSequence::filtreCalculSousSequence(threadPrincipal *p_thread) : tbb::filter(serial_in_order) {
	this->thread = p_thread;
	this->a = 0;
	this->b = 0;
}

filtreCalculSousSequence::~filtreCalculSousSequence() {

}

void* filtreCalculSousSequence::operator ()(void* item) {
	if(item == NULL)
		return NULL;
	struct structCGH *structure = static_cast<struct structCGH*>(item);

	this->tabCgh = structure->cgh;
	this->g = structure->g;
	this->h = structure->h;

	this->launchCalcul();
	this->computeM();
	this->findAB();
	this->compareResults();

	return NULL;
}

int filtreCalculSousSequence::launchCalcul() {
	//Création de la tache de calcul des PSUM :
	this->psum = new tbb::concurrent_vector<int>();
	this->smax = new tbb::concurrent_vector<int>();
	taskPsumSmax& taskPsumSmaxComputing = *new (tbb::task::allocate_root()) taskPsumSmax(this->tabCgh, this->psum, this->smax);
	//Création de la tache de calcul des SSUM :
	this->ssum = new tbb::concurrent_vector<int>();
	this->pmax = new tbb::concurrent_vector<int>();
	taskSsumPmax& taskSsumPmaxComputing = *new (tbb::task::allocate_root()) taskSsumPmax(this->tabCgh, this->ssum, this->pmax);

	tbb::task::spawn_root_and_wait( taskPsumSmaxComputing );
	tbb::task::spawn_root_and_wait( taskSsumPmaxComputing );
	return 0;
}

int filtreCalculSousSequence::computeM() {
	this->M = new tbb::concurrent_vector<int>();
	this->tabSize = (*(this->tabCgh)).size();

	for(int i=0; i < tabSize; i++) {
		(*(this->M)).push_back( (*(this->pmax))[i] + (*(this->smax))[i] + (*(this->tabCgh))[i] - (*(this->ssum))[i] - (*(this->psum))[i] );
	}

	return 0;
}

int filtreCalculSousSequence::findAB() {
	this->b=0;
	for(int i=1; i<this->tabSize; i++) {
		if( (*(this->M))[i] > (*(this->M))[a] ) {
			this->a = i;
			this->b = i;
		}
		else if( (*(this->M))[i] == (*(this->M))[a]) {
			this->b++;
		}
	}
	return 0;
}

int filtreCalculSousSequence::compareResults() {
	struct result *resultFinal = (*(this->thread)).getStructureResult();
	tbb::spin_rw_mutex_v3::scoped_lock lock;
	//Acquisition de la mutex en lecture
	lock.acquire((*(this->thread)).mutexControlResult, false);
	if((*(this->M))[a] > resultFinal->S) {
		lock.release();
		lock.acquire((*(this->thread)).mutexControlResult, true);
		if((*(this->M))[a] > resultFinal->S) {
			resultFinal->S = (*(this->M))[a];
			resultFinal->a = this->a;
			resultFinal->b = this->b;
			resultFinal->g = this->g - 1;
			resultFinal->h = this->h - 1;
		}
		lock.release();
	}
	else {
		lock.release();
	}
	delete this->M;
	delete this->tabCgh;
	delete this->pmax;
	delete this->psum;
	delete this->smax;
	delete this->ssum;
	return 0;
}
